#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import cv2
import numpy as np
import re
from typing import Dict, Optional, Tuple, List
from dataclasses import dataclass
from pathlib import Path
import datetime
import os
from PIL import Image, ImageEnhance, ImageFilter
import time
import math
from concurrent.futures import ThreadPoolExecutor
import gc
import json
import logging

# OCR引擎配置
USE_RAPID_OCR = True  # 使用RapidOCR引擎

# 导入OCR引擎
try:
    from rapidocr_onnxruntime import RapidOCR
except ImportError:
    RapidOCR = None

try:
    from paddleocr import PaddleOCR
except ImportError:
    PaddleOCR = None

# 导入错误处理模块
from .business_license_errors import (
    BusinessLicenseError,
    BusinessLicenseErrorType,
    BusinessLicenseFileError,
    BusinessLicenseOCRError,
    BusinessLicenseRecognitionError,
    BusinessLicenseValidationError,
    BusinessLicenseSystemError,
    business_license_error_handler
)

class BusinessLicenseValidator:
    """营业执照数据验证器"""
    
    @staticmethod
    def validate_unified_social_credit_code(code: str) -> dict:
        """验证统一社会信用代码
        
        Args:
            code: 统一社会信用代码字符串
            
        Returns:
            dict: 验证结果，包含valid、error_message等字段
        """
        if not code:
            return {
                'valid': False,
                'error_message': '统一社会信用代码不能为空',
                'error_type': 'empty_code'
            }
        
        # 移除空格和特殊字符
        code = re.sub(r'[^\w]', '', code.upper())
        
        # 长度检查
        if len(code) != 18:
            return {
                'valid': False,
                'error_message': f'统一社会信用代码长度应为18位，实际为{len(code)}位',
                'error_type': 'invalid_length'
            }
        
        # 格式检查 - 先检查是否包含无效字符
        invalid_chars = re.findall(r'[IOVZ]', code)
        if invalid_chars:
            return {
                'valid': False,
                'error_message': f'统一社会信用代码包含无效字符: {", ".join(invalid_chars)}',
                'error_type': 'invalid_format'
            }
        
        # 检查整体格式
        pattern = r'^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$'
        if not re.match(pattern, code):
            return {
                'valid': False,
                'error_message': '统一社会信用代码格式不正确',
                'error_type': 'invalid_format'
            }
        
        # 校验码验证
        check_result = BusinessLicenseValidator._validate_credit_code_checksum(code)
        if not check_result['valid']:
            return check_result
        
        return {
            'valid': True,
            'formatted_code': code,
            'error_message': None,
            'error_type': None
        }
    
    @staticmethod
    def _validate_credit_code_checksum(code: str) -> dict:
        """验证统一社会信用代码校验码
        
        使用GB 32100-2015标准的校验算法
        """
        # 字符映射表
        char_map = {
            '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
            'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15, 'G': 16, 'H': 17, 'J': 18,
            'K': 19, 'L': 20, 'M': 21, 'N': 22, 'P': 23, 'Q': 24, 'R': 25, 'T': 26, 'U': 27,
            'W': 28, 'X': 29, 'Y': 30
        }
        
        # 权重数组
        weights = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28]
        
        try:
            # 计算前17位的加权和
            total = 0
            for i in range(17):
                char = code[i]
                if char not in char_map:
                    return {
                        'valid': False,
                        'error_message': f'统一社会信用代码包含无效字符: {char}',
                        'error_type': 'invalid_character'
                    }
                total += char_map[char] * weights[i]
            
            # 计算校验码
            remainder = total % 31
            check_digit = 31 - remainder if remainder != 0 else 0
            
            # 校验码字符映射
            check_char_map = {
                0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9',
                10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F', 16: 'G', 17: 'H', 18: 'J',
                19: 'K', 20: 'L', 21: 'M', 22: 'N', 23: 'P', 24: 'Q', 25: 'R', 26: 'T', 27: 'U',
                28: 'W', 29: 'X', 30: 'Y'
            }
            
            expected_check_char = check_char_map[check_digit]
            actual_check_char = code[17]
            
            if expected_check_char != actual_check_char:
                return {
                    'valid': False,
                    'error_message': f'统一社会信用代码校验码错误，期望: {expected_check_char}，实际: {actual_check_char}',
                    'error_type': 'invalid_checksum'
                }
            
            return {
                'valid': True,
                'error_message': None,
                'error_type': None
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error_message': f'校验码验证过程中发生错误: {str(e)}',
                'error_type': 'validation_error'
            }
    
    @staticmethod
    def validate_registration_number(number: str) -> dict:
        """验证注册号（旧版营业执照）
        
        Args:
            number: 注册号字符串
            
        Returns:
            dict: 验证结果
        """
        if not number:
            return {
                'valid': False,
                'error_message': '注册号不能为空',
                'error_type': 'empty_number'
            }
        
        # 移除空格和特殊字符
        number = re.sub(r'[^\d]', '', number)
        
        # 长度检查
        if len(number) != 15:
            return {
                'valid': False,
                'error_message': f'注册号长度应为15位，实际为{len(number)}位',
                'error_type': 'invalid_length'
            }
        
        # 格式检查（全数字）
        if not number.isdigit():
            return {
                'valid': False,
                'error_message': '注册号应为15位数字',
                'error_type': 'invalid_format'
            }
        
        return {
            'valid': True,
            'formatted_number': number,
            'error_message': None,
            'error_type': None
        }
    
    @staticmethod
    def validate_date_format(date_str: str) -> dict:
        """验证日期格式
        
        Args:
            date_str: 日期字符串
            
        Returns:
            dict: 验证结果
        """
        if not date_str:
            return {
                'valid': False,
                'error_message': '日期不能为空',
                'error_type': 'empty_date'
            }
        
        # 支持的日期格式
        date_patterns = [
            (r'(\d{4})年(\d{1,2})月(\d{1,2})日', '%Y年%m月%d日'),
            (r'(\d{4})-(\d{2})-(\d{2})', '%Y-%m-%d'),  # 严格要求两位数的月日
            (r'(\d{4})/(\d{2})/(\d{2})', '%Y/%m/%d'),  # 严格要求两位数的月日
            (r'(\d{4})\.(\d{2})\.(\d{2})', '%Y.%m.%d'), # 严格要求两位数的月日
        ]
        
        for pattern, format_str in date_patterns:
            match = re.search(pattern, date_str)
            if match:
                try:
                    year, month, day = match.groups()
                    # 验证日期有效性
                    datetime.datetime(int(year), int(month), int(day))
                    
                    # 格式化日期
                    formatted_date = f"{year}年{month.zfill(2)}月{day.zfill(2)}日"
                    
                    return {
                        'valid': True,
                        'formatted_date': formatted_date,
                        'year': int(year),
                        'month': int(month),
                        'day': int(day),
                        'error_message': None,
                        'error_type': None
                    }
                except ValueError:
                    continue
        
        return {
            'valid': False,
            'error_message': f'无法识别的日期格式: {date_str}',
            'error_type': 'invalid_format'
        }
    
    @staticmethod
    def validate_business_license_info(info) -> dict:
        """验证营业执照信息完整性
        
        Args:
            info: BusinessLicenseInfo对象
            
        Returns:
            dict: 验证结果
        """
        validation_result = {
            'valid': True,
            'errors': [],
            'warnings': [],
            'field_validations': {}
        }
        
        # 检查关键字段
        required_fields = ['company_name', 'legal_representative']
        
        # 根据版本检查不同的必需字段
        if info.license_version == 'new':
            required_fields.append('unified_social_credit_code')
        elif info.license_version == 'old':
            required_fields.append('registration_number')
        
        # 验证必需字段
        for field in required_fields:
            value = getattr(info, field, None)
            if not value or not value.strip():
                validation_result['valid'] = False
                validation_result['errors'].append(f'缺少必需字段: {field}')
                validation_result['field_validations'][field] = {
                    'valid': False,
                    'error': '字段为空'
                }
            else:
                validation_result['field_validations'][field] = {
                    'valid': True,
                    'value': value.strip()
                }
        
        # 验证统一社会信用代码
        if info.unified_social_credit_code:
            credit_validation = BusinessLicenseValidator.validate_unified_social_credit_code(
                info.unified_social_credit_code
            )
            validation_result['field_validations']['unified_social_credit_code'] = credit_validation
            if not credit_validation['valid']:
                validation_result['valid'] = False
                validation_result['errors'].append(credit_validation['error_message'])
        
        # 验证注册号
        if info.registration_number:
            reg_validation = BusinessLicenseValidator.validate_registration_number(
                info.registration_number
            )
            validation_result['field_validations']['registration_number'] = reg_validation
            if not reg_validation['valid']:
                validation_result['valid'] = False
                validation_result['errors'].append(reg_validation['error_message'])
        
        # 验证日期字段
        date_fields = ['establishment_date', 'approval_date']
        for field in date_fields:
            value = getattr(info, field, None)
            if value:
                date_validation = BusinessLicenseValidator.validate_date_format(value)
                validation_result['field_validations'][field] = date_validation
                if not date_validation['valid']:
                    validation_result['warnings'].append(f'{field}: {date_validation["error_message"]}')
        
        return validation_result

@dataclass
class BusinessLicenseInfo:
    """营业执照信息数据结构"""
    # 基本信息
    company_name: Optional[str] = None              # 企业名称
    unified_social_credit_code: Optional[str] = None # 统一社会信用代码
    legal_representative: Optional[str] = None       # 法定代表人
    registered_capital: Optional[str] = None         # 注册资本
    establishment_date: Optional[str] = None         # 成立日期
    business_term: Optional[str] = None              # 营业期限
    
    # 详细信息
    business_scope: Optional[str] = None             # 经营范围
    company_type: Optional[str] = None               # 公司类型
    registration_authority: Optional[str] = None     # 登记机关
    approval_date: Optional[str] = None              # 核准日期
    registered_address: Optional[str] = None         # 注册地址
    
    # 旧版营业执照特有字段
    registration_number: Optional[str] = None        # 注册号（旧版）
    
    # 识别结果元信息
    license_version: Optional[str] = None            # 营业执照版本：'new' 或 'old'
    
    def to_dict(self) -> Dict:
        """转换为字典格式"""
        return {
            'company_name': self.company_name,
            'unified_social_credit_code': self.unified_social_credit_code,
            'legal_representative': self.legal_representative,
            'registered_capital': self.registered_capital,
            'establishment_date': self.establishment_date,
            'business_term': self.business_term,
            'business_scope': self.business_scope,
            'company_type': self.company_type,
            'registration_authority': self.registration_authority,
            'approval_date': self.approval_date,
            'registered_address': self.registered_address,
            'registration_number': self.registration_number,
            'license_version': self.license_version
        }

class BusinessLicenseReader:
    """营业执照OCR识别器"""
    
    def __init__(self, use_fast_mode=True, max_image_size=1920, logger=None):
        """初始化营业执照读取器
        
        Args:
            use_fast_mode (bool): 是否使用快速模式，影响OCR精度和速度平衡
            max_image_size (int): 图像处理的最大尺寸，超过此尺寸将被缩放
            logger: 日志记录器，如果为None则创建默认logger
        """
        self.use_fast_mode = use_fast_mode
        self.max_image_size = max_image_size
        
        # 设置日志记录器
        self.logger = logger or logging.getLogger(__name__)
        
        # 加载配置文件
        self.config = self._load_config()
        
        # 初始化OCR引擎
        self._init_ocr_engines()
        
        # 图像预处理参数
        self.preprocess_params = {
            'gaussian_blur_kernel': (3, 3),
            'bilateral_filter_d': 9,
            'bilateral_filter_sigma_color': 75,
            'bilateral_filter_sigma_space': 75,
            'morphology_kernel_size': (2, 2),
            'contrast_alpha': 1.2,
            'brightness_beta': 10
        }
    
    def _init_ocr_engines(self):
        """初始化OCR引擎，支持RapidOCR和PaddleOCR"""
        try:
            if USE_RAPID_OCR:
                # 使用RapidOCR作为主引擎
                self.ocr = RapidOCR()
                self.ocr_backup = None
                self.logger.info("使用RapidOCR引擎进行营业执照识别")
            else:
                # 使用PaddleOCR作为主引擎
                self.ocr = PaddleOCR(
                    use_angle_cls=True,
                    use_gpu=False,
                    lang='ch',
                    show_log=False,
                    det_db_thresh=0.2 if self.use_fast_mode else 0.15,
                    det_db_box_thresh=0.5 if self.use_fast_mode else 0.4,
                    det_db_unclip_ratio=1.8 if self.use_fast_mode else 2.0,
                    det_max_side_len=1280 if self.use_fast_mode else 1920,
                    enable_mkldnn=True,
                    cpu_threads=2,
                    rec_batch_num=1,
                )
                
                # 如果不是快速模式，创建备用高精度引擎
                if not self.use_fast_mode:
                    self.ocr_backup = PaddleOCR(
                        use_angle_cls=True,
                        use_gpu=False,
                        lang='ch',
                        show_log=False,
                        det_db_thresh=0.1,
                        det_db_box_thresh=0.3,
                        det_db_unclip_ratio=2.2,
                        det_max_side_len=2048,
                        enable_mkldnn=True,
                        cpu_threads=2,
                        rec_batch_num=1,
                    )
                else:
                    self.ocr_backup = None
                    
                self.logger.info("使用PaddleOCR引擎进行营业执照识别")
                
        except ImportError as e:
            error = BusinessLicenseOCRError(
                BusinessLicenseErrorType.OCR_ENGINE_INIT_FAILED,
                f"OCR引擎依赖库导入失败: {str(e)}",
                {'use_rapid_ocr': USE_RAPID_OCR},
                e
            )
            self.logger.error(f"OCR引擎初始化失败: {error.message}")
            raise error
        except Exception as e:
            error = BusinessLicenseOCRError(
                BusinessLicenseErrorType.OCR_ENGINE_INIT_FAILED,
                f"OCR引擎初始化失败: {str(e)}",
                {'use_rapid_ocr': USE_RAPID_OCR},
                e
            )
            self.logger.error(f"OCR引擎初始化失败: {error.message}")
            raise error
    
    def _load_config(self) -> Dict:
        """加载营业执照配置文件"""
        config_path = os.path.join(os.path.dirname(__file__), 'business_license_config.json')
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except FileNotFoundError:
            # 如果配置文件不存在，返回默认配置
            return self._get_default_config()
    
    def _get_default_config(self) -> Dict:
        """获取默认配置"""
        return {
            "version_detection": {
                "new_version_keywords": ["统一社会信用代码", "名称", "类型", "住所"],
                "old_version_keywords": ["注册号", "企业名称", "企业类型", "企业住所"],
                "credit_code_pattern": "^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$",
                "registration_number_pattern": "^\\d{15}$"
            },
            "field_mapping": {
                "new_version": {
                    "company_name": ["名称"],
                    "legal_representative": ["法定代表人"],
                    "registered_address": ["住所"]
                },
                "old_version": {
                    "company_name": ["企业名称"],
                    "legal_representative": ["法定代表人"],
                    "registered_address": ["企业住所", "住所"]
                }
            }
        }
    
    def read_business_license(self, image_path: str) -> BusinessLicenseInfo:
        """识别营业执照信息
        
        Args:
            image_path: 营业执照图片路径
            
        Returns:
            BusinessLicenseInfo: 识别结果
            
        Raises:
            BusinessLicenseError: 识别过程中的各种错误
        """
        start_time = time.time()
        self.logger.info(f"开始识别营业执照: {image_path}")
        
        try:
            # 验证文件存在性
            if not os.path.exists(image_path):
                raise BusinessLicenseFileError(
                    BusinessLicenseErrorType.FILE_NOT_FOUND,
                    f"图像文件不存在: {image_path}",
                    {'image_path': image_path}
                )
            
            # 图像预处理
            self.logger.debug("开始图像预处理")
            try:
                processed_image = self._preprocess_image(image_path)
            except Exception as e:
                if isinstance(e, BusinessLicenseError):
                    raise
                raise BusinessLicenseOCRError(
                    BusinessLicenseErrorType.OCR_IMAGE_PREPROCESSING_FAILED,
                    f"图像预处理失败: {str(e)}",
                    {'image_path': image_path},
                    e
                )
            
            # OCR文本提取
            self.logger.debug("开始OCR文本提取")
            ocr_results = self._extract_text_with_positions(processed_image)
            
            # 检查是否提取到文本
            if not ocr_results:
                raise BusinessLicenseOCRError(
                    BusinessLicenseErrorType.OCR_NO_TEXT_DETECTED,
                    "未检测到任何文本内容，请确保图片清晰且包含营业执照",
                    {'image_path': image_path, 'ocr_results_count': 0}
                )
            
            self.logger.debug(f"OCR提取到 {len(ocr_results)} 个文本块")
            
            # 检测营业执照版本
            self.logger.debug("开始版本检测")
            try:
                version = self._detect_license_version(ocr_results)
            except Exception as e:
                raise BusinessLicenseRecognitionError(
                    BusinessLicenseErrorType.RECOGNITION_VERSION_DETECTION_FAILED,
                    f"营业执照版本检测失败: {str(e)}",
                    {'image_path': image_path, 'ocr_results_count': len(ocr_results)},
                    e
                )
            
            self.logger.debug(f"检测到营业执照版本: {version}")
            
            # 根据版本提取字段
            self.logger.debug("开始字段提取")
            try:
                license_info = self._extract_fields_by_version(ocr_results, version)
                license_info.license_version = version
            except Exception as e:
                raise BusinessLicenseRecognitionError(
                    BusinessLicenseErrorType.RECOGNITION_FIELD_EXTRACTION_FAILED,
                    f"字段提取失败: {str(e)}",
                    {'image_path': image_path, 'version': version},
                    e
                )
            
            # 验证识别结果
            key_fields_found = any([
                license_info.company_name and license_info.company_name.strip(),
                license_info.unified_social_credit_code and license_info.unified_social_credit_code.strip(),
                license_info.registration_number and license_info.registration_number.strip(),
                license_info.legal_representative and license_info.legal_representative.strip()
            ])
            
            if not key_fields_found:
                raise BusinessLicenseRecognitionError(
                    BusinessLicenseErrorType.RECOGNITION_NO_KEY_FIELDS,
                    "未识别到营业执照关键信息，请确保图片清晰且包含完整的营业执照内容",
                    {
                        'image_path': image_path,
                        'version': version,
                        'ocr_results_count': len(ocr_results),
                        'extracted_fields': license_info.to_dict()
                    }
                )
            
            # 记录成功信息
            processing_time = time.time() - start_time
            self.logger.info(f"营业执照识别成功: {image_path}, 版本: {version}, 耗时: {processing_time:.2f}秒")
            
            return license_info
            
        except BusinessLicenseError:
            # 重新抛出业务异常
            processing_time = time.time() - start_time
            self.logger.error(f"营业执照识别失败: {image_path}, 耗时: {processing_time:.2f}秒")
            raise
        except Exception as e:
            # 包装未知异常
            processing_time = time.time() - start_time
            error = BusinessLicenseSystemError(
                BusinessLicenseErrorType.SYSTEM_INTERNAL_ERROR,
                f"营业执照识别过程中发生未知错误: {str(e)}",
                {'image_path': image_path, 'processing_time': processing_time},
                e
            )
            self.logger.error(f"营业执照识别发生未知错误: {error.message}")
            raise error
    
    def _detect_license_version(self, ocr_results: List[Tuple]) -> str:
        """检测营业执照版本类型
        
        通过多种特征综合判断营业执照版本：
        1. 关键词检测
        2. 格式特征检测
        3. 版式布局特征
        
        Returns:
            str: 'new' 表示新版（2016年后），'old' 表示旧版（2016年前）
        """
        # 提取所有文本
        all_text = ' '.join([result[1] for result in ocr_results if len(result) > 1])
        
        # 初始化评分
        new_version_score = 0
        old_version_score = 0
        
        # 1. 关键词检测
        new_keywords = self.config["version_detection"]["new_version_keywords"]
        old_keywords = self.config["version_detection"]["old_version_keywords"]
        
        # 检查新版关键词
        for keyword in new_keywords:
            if keyword in all_text:
                new_version_score += 1
                # "统一社会信用代码"是新版的强特征
                if keyword == "统一社会信用代码":
                    new_version_score += 3
        
        # 检查旧版关键词
        for keyword in old_keywords:
            if keyword in all_text:
                old_version_score += 1
                # "注册号"是旧版的强特征（但要排除新版中可能出现的情况）
                if keyword == "注册号" and "统一社会信用代码" not in all_text:
                    old_version_score += 3
        
        # 2. 格式特征检测
        credit_code_pattern = self.config["version_detection"]["credit_code_pattern"]
        reg_number_pattern = self.config["version_detection"]["registration_number_pattern"]
        
        # 检查统一社会信用代码格式（18位）
        credit_codes = re.findall(credit_code_pattern, all_text)
        if credit_codes:
            new_version_score += 5  # 这是新版的决定性特征
            # 进一步验证统一社会信用代码的有效性
            for code in credit_codes:
                validation = BusinessLicenseValidator.validate_unified_social_credit_code(code)
                if validation['valid']:
                    new_version_score += 3  # 有效的统一社会信用代码强烈表明是新版
                    break
        
        # 检查注册号格式（15位数字）
        reg_numbers = re.findall(reg_number_pattern, all_text)
        if reg_numbers:
            # 只有在没有统一社会信用代码的情况下，注册号才是旧版的强特征
            if not credit_codes:
                old_version_score += 5
            else:
                # 如果同时存在，可能是过渡期证照，倾向于新版
                new_version_score += 1
        
        # 3. 版式布局特征检测
        layout_score = self._analyze_layout_features(ocr_results)
        new_version_score += layout_score['new_version_score']
        old_version_score += layout_score['old_version_score']
        
        # 4. 特殊情况处理
        # 检查是否包含"三证合一"相关信息
        if "三证合一" in all_text or "一照一码" in all_text:
            new_version_score += 2
        
        # 检查日期信息（2016年后的日期倾向于新版）
        date_score = self._analyze_date_features(all_text)
        new_version_score += date_score['new_version_score']
        old_version_score += date_score['old_version_score']
        
        # 决策逻辑
        if new_version_score > old_version_score:
            return 'new'
        elif old_version_score > new_version_score:
            return 'old'
        else:
            # 分数相等时，默认判断为新版（因为新版更常见）
            return 'new'
    
    def _analyze_layout_features(self, ocr_results: List[Tuple]) -> dict:
        """分析版式布局特征
        
        Args:
            ocr_results: OCR识别结果
            
        Returns:
            dict: 包含新版和旧版评分的字典
        """
        new_score = 0
        old_score = 0
        
        # 提取文本内容
        texts = [result[1] for result in ocr_results if len(result) > 1]
        
        # 新版营业执照的典型布局特征
        new_layout_indicators = [
            "中华人民共和国营业执照",  # 新版标题
            "名称",  # 新版使用"名称"而不是"企业名称"
            "类型",  # 新版使用"类型"而不是"企业类型"
            "住所",  # 新版使用"住所"
        ]
        
        # 旧版营业执照的典型布局特征
        old_layout_indicators = [
            "企业法人营业执照",  # 旧版标题
            "企业名称",
            "企业类型",
            "企业住所",
            "经济性质",  # 旧版特有字段
        ]
        
        # 统计新版布局特征
        for indicator in new_layout_indicators:
            for text in texts:
                if indicator in text:
                    new_score += 1
                    break
        
        # 统计旧版布局特征
        for indicator in old_layout_indicators:
            for text in texts:
                if indicator in text:
                    old_score += 1
                    break
        
        return {
            'new_version_score': new_score,
            'old_version_score': old_score
        }
    
    def _analyze_date_features(self, all_text: str) -> dict:
        """分析日期特征
        
        Args:
            all_text: 所有OCR文本
            
        Returns:
            dict: 包含新版和旧版评分的字典
        """
        new_score = 0
        old_score = 0
        
        # 提取年份信息
        year_pattern = r'(\d{4})年'
        years = re.findall(year_pattern, all_text)
        
        for year_str in years:
            try:
                year = int(year_str)
                # 2016年是三证合一改革的分界点
                if year >= 2016:
                    new_score += 1
                elif year < 2016:
                    old_score += 1
            except ValueError:
                continue
        
        return {
            'new_version_score': new_score,
            'old_version_score': old_score
        }
    
    def _preprocess_image(self, image_path: str) -> np.ndarray:
        """图像预处理
        
        包括尺寸调整、灰度化、噪声去除、对比度增强等步骤
        
        Args:
            image_path (str): 图像文件路径
            
        Returns:
            np.ndarray: 预处理后的图像
            
        Raises:
            ValueError: 当无法读取图像文件时
        """
        # 读取图像
        try:
            image = cv2.imread(image_path)
            if image is None:
                raise BusinessLicenseFileError(
                    BusinessLicenseErrorType.FILE_CORRUPTED,
                    f"无法读取图像文件，可能文件损坏或格式不支持: {image_path}",
                    {'image_path': image_path}
                )
        except Exception as e:
            if isinstance(e, BusinessLicenseFileError):
                raise
            raise BusinessLicenseFileError(
                BusinessLicenseErrorType.FILE_READ_ERROR,
                f"读取图像文件时发生错误: {str(e)}",
                {'image_path': image_path},
                e
            )
        
        # 1. 尺寸调整 - 保持长宽比
        image = self._resize_image(image)
        
        # 2. 图像增强处理
        image = self._enhance_image(image)
        
        # 3. 噪声去除
        image = self._denoise_image(image)
        
        # 4. 对比度和亮度调整
        image = self._adjust_contrast_brightness(image)
        
        return image
    
    def _resize_image(self, image: np.ndarray) -> np.ndarray:
        """调整图像大小，保持长宽比
        
        Args:
            image (np.ndarray): 输入图像
            
        Returns:
            np.ndarray: 调整大小后的图像
        """
        height, width = image.shape[:2]
        
        # 如果图像尺寸超过最大限制，按比例缩放
        if max(height, width) > self.max_image_size:
            scale = self.max_image_size / max(height, width)
            new_width = int(width * scale)
            new_height = int(height * scale)
            
            # 使用INTER_AREA插值方法，适合缩小图像
            image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_AREA)
        
        # 如果图像太小，适当放大以提高OCR效果
        elif max(height, width) < 800:
            scale = 800 / max(height, width)
            new_width = int(width * scale)
            new_height = int(height * scale)
            
            # 使用INTER_CUBIC插值方法，适合放大图像
            image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_CUBIC)
        
        return image
    
    def _enhance_image(self, image: np.ndarray) -> np.ndarray:
        """图像增强处理
        
        Args:
            image (np.ndarray): 输入图像
            
        Returns:
            np.ndarray: 增强后的图像
        """
        # 转换为灰度图像
        if len(image.shape) == 3:
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        else:
            gray = image.copy()
        
        # 自适应直方图均衡化，提高对比度
        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        enhanced = clahe.apply(gray)
        
        # 转换回BGR格式以保持一致性
        if len(image.shape) == 3:
            enhanced = cv2.cvtColor(enhanced, cv2.COLOR_GRAY2BGR)
        
        return enhanced
    
    def _denoise_image(self, image: np.ndarray) -> np.ndarray:
        """噪声去除
        
        Args:
            image (np.ndarray): 输入图像
            
        Returns:
            np.ndarray: 去噪后的图像
        """
        # 使用双边滤波去除噪声，同时保持边缘
        params = self.preprocess_params
        denoised = cv2.bilateralFilter(
            image,
            params['bilateral_filter_d'],
            params['bilateral_filter_sigma_color'],
            params['bilateral_filter_sigma_space']
        )
        
        # 轻微的高斯模糊，进一步减少噪声
        denoised = cv2.GaussianBlur(denoised, params['gaussian_blur_kernel'], 0)
        
        # 形态学操作，去除小的噪声点
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, params['morphology_kernel_size'])
        denoised = cv2.morphologyEx(denoised, cv2.MORPH_CLOSE, kernel)
        
        return denoised
    
    def _adjust_contrast_brightness(self, image: np.ndarray) -> np.ndarray:
        """调整对比度和亮度
        
        Args:
            image (np.ndarray): 输入图像
            
        Returns:
            np.ndarray: 调整后的图像
        """
        params = self.preprocess_params
        
        # 应用对比度和亮度调整
        # new_image = alpha * image + beta
        adjusted = cv2.convertScaleAbs(
            image,
            alpha=params['contrast_alpha'],
            beta=params['brightness_beta']
        )
        
        return adjusted
    
    def _extract_text_with_positions(self, image: np.ndarray) -> List[Tuple]:
        """提取文本和位置信息
        
        使用OCR引擎提取图像中的文本内容及其位置信息
        
        Args:
            image (np.ndarray): 预处理后的图像
            
        Returns:
            List[Tuple]: 包含(bbox, text, confidence)的元组列表
                - bbox: 文本框坐标 [[x1,y1], [x2,y2], [x3,y3], [x4,y4]]
                - text: 识别的文本内容
                - confidence: 置信度分数
        """
        results = []
        
        try:
            if USE_RAPID_OCR:
                results = self._extract_with_rapidocr(image)
            else:
                results = self._extract_with_paddleocr(image)
                
            # 如果主引擎结果不理想且有备用引擎，尝试备用引擎
            if not self.use_fast_mode and len(results) < 5 and self.ocr_backup:
                try:
                    backup_results = self._extract_with_paddleocr(image, use_backup=True)
                    if len(backup_results) > len(results):
                        results = backup_results
                        self.logger.debug("使用备用OCR引擎获得更好结果")
                except Exception as backup_e:
                    self.logger.warning(f"备用OCR引擎失败: {str(backup_e)}")
                    
        except Exception as e:
            error = BusinessLicenseOCRError(
                BusinessLicenseErrorType.OCR_TEXT_EXTRACTION_FAILED,
                f"OCR文本提取失败: {str(e)}",
                {'use_rapid_ocr': USE_RAPID_OCR},
                e
            )
            self.logger.error(f"OCR文本提取失败: {error.message}")
            raise error
        
        # 过滤和清理结果
        filtered_results = self._filter_ocr_results(results)
        
        return filtered_results
    
    def _extract_with_rapidocr(self, image: np.ndarray) -> List[Tuple]:
        """使用RapidOCR提取文本
        
        Args:
            image (np.ndarray): 输入图像
            
        Returns:
            List[Tuple]: OCR结果列表
        """
        results = []
        
        ocr_result = self.ocr(image)

        # 记录OCR原始结果用于调试
        self.logger.info("=" * 80)
        self.logger.info("RapidOCR原始识别结果:")
        self.logger.info("=" * 80)
        self.logger.info(f"OCR结果类型: {type(ocr_result)}")
        self.logger.info(f"OCR结果内容: {ocr_result}")
        self.logger.info("=" * 80)

        # 处理RapidOCR的返回格式
        if isinstance(ocr_result, tuple) and len(ocr_result) >= 2:
            result, elapse = ocr_result
        else:
            result = ocr_result
        
        if result:
            for line in result:
                if isinstance(line, list) and len(line) >= 3:
                    bbox = line[0]
                    text = line[1]
                    confidence = line[2]
                    
                    # 验证数据有效性
                    if (confidence > 0.1 and 
                        text and 
                        str(text).strip() and 
                        isinstance(bbox, list) and 
                        len(bbox) == 4):
                        
                        results.append((bbox, str(text).strip(), confidence))
        
        return results
    
    def _extract_with_paddleocr(self, image: np.ndarray, use_backup: bool = False) -> List[Tuple]:
        """使用PaddleOCR提取文本
        
        Args:
            image (np.ndarray): 输入图像
            use_backup (bool): 是否使用备用高精度引擎
            
        Returns:
            List[Tuple]: OCR结果列表
        """
        results = []
        
        # 选择使用的OCR引擎
        ocr_engine = self.ocr_backup if use_backup and self.ocr_backup else self.ocr
        
        ocr_result = ocr_engine.ocr(image, cls=True)

        # 记录PaddleOCR原始结果用于调试
        self.logger.info("=" * 80)
        self.logger.info("PaddleOCR原始识别结果:")
        self.logger.info("=" * 80)
        self.logger.info(f"OCR结果类型: {type(ocr_result)}")
        self.logger.info(f"OCR结果内容: {ocr_result}")
        self.logger.info("=" * 80)

        if ocr_result and len(ocr_result) > 0:
            # 处理PaddleOCR的嵌套列表结构
            ocr_data = ocr_result[0] if isinstance(ocr_result[0], list) else ocr_result
            
            for line in ocr_data:
                if isinstance(line, list) and len(line) >= 2:
                    bbox = line[0]
                    text_info = line[1]
                    
                    # 提取文本和置信度
                    if isinstance(text_info, list) and len(text_info) >= 2:
                        text = str(text_info[0]).strip()
                        confidence = float(text_info[1])
                    else:
                        text = str(text_info).strip()
                        confidence = 1.0
                    
                    # 验证数据有效性
                    if (confidence > 0.1 and 
                        text and 
                        isinstance(bbox, list) and 
                        len(bbox) == 4):
                        
                        results.append((bbox, text, confidence))
        
        return results
    
    def _filter_ocr_results(self, results: List[Tuple]) -> List[Tuple]:
        """过滤和清理OCR结果
        
        Args:
            results (List[Tuple]): 原始OCR结果
            
        Returns:
            List[Tuple]: 过滤后的结果
        """
        filtered_results = []
        
        for bbox, text, confidence in results:
            # 清理文本
            cleaned_text = self._clean_text(text)
            
            # 过滤条件
            if (cleaned_text and 
                len(cleaned_text) > 0 and 
                confidence > 0.1 and
                not self._is_noise_text(cleaned_text)):
                
                filtered_results.append((bbox, cleaned_text, confidence))
        
        # 按置信度排序
        filtered_results.sort(key=lambda x: x[2], reverse=True)
        
        return filtered_results
    
    def _is_noise_text(self, text: str) -> bool:
        """判断是否为噪声文本
        
        Args:
            text (str): 文本内容
            
        Returns:
            bool: 是否为噪声文本
        """
        # 过滤单个字符或过短的文本
        if len(text) < 2:
            return True
        
        # 过滤纯符号文本
        if re.match(r'^[^\u4e00-\u9fff\w]+$', text):
            return True
        
        # 过滤重复字符
        if len(set(text)) == 1 and len(text) > 3:
            return True
        
        return False
    
    def _extract_fields_by_version(self, ocr_results: List[Tuple], version: str) -> BusinessLicenseInfo:
        """根据版本类型提取字段"""
        if version == 'new':
            return self._extract_new_version_fields(ocr_results)
        else:
            return self._extract_old_version_fields(ocr_results)
    
    def _extract_new_version_fields(self, ocr_results: List[Tuple]) -> BusinessLicenseInfo:
        """提取新版营业执照字段（2016年后）
        
        使用基于关键词和位置的字段定位算法，提高字段提取的准确性
        
        Args:
            ocr_results: OCR识别结果列表，包含(bbox, text, confidence)
            
        Returns:
            BusinessLicenseInfo: 提取的营业执照信息
        """
        info = BusinessLicenseInfo()
        
        # 获取新版字段映射配置
        field_mapping = self.config["field_mapping"]["new_version"]
        
        # 构建文本位置映射
        text_positions = self._build_text_position_map(ocr_results)
        
        # 提取各个字段
        for field_name, keywords in field_mapping.items():
            self.logger.info(f"提取字段: {field_name}, 关键词: {keywords}")
            extracted_value = self._extract_field_by_keywords_and_position(
                text_positions, keywords, field_name
            )
            self.logger.info(f"字段 {field_name} 提取原始值: {extracted_value}")

            if extracted_value:
                # 清理和格式化文本
                cleaned_value = self._clean_and_format_field_text(extracted_value, field_name)
                self.logger.info(f"字段 {field_name} 清理后值: {cleaned_value}")
                if cleaned_value:
                    setattr(info, field_name, cleaned_value)
        
        # 特殊处理：统一社会信用代码的精确提取
        if not info.unified_social_credit_code:
            info.unified_social_credit_code = self._extract_credit_code_precise(ocr_results)
        
        # 特殊处理：企业名称的精确提取
        if not info.company_name:
            info.company_name = self._extract_company_name_precise(ocr_results)
        
        # 特殊处理：经营范围的多行文本提取
        if not info.business_scope:
            info.business_scope = self._extract_business_scope_multiline(ocr_results)
        
        return info
    
    def _extract_old_version_fields(self, ocr_results: List[Tuple]) -> BusinessLicenseInfo:
        """提取旧版营业执照字段（2016年前）
        
        旧版营业执照具有以下特点：
        1. 使用15位注册号而非统一社会信用代码
        2. 不同地区的版式差异较大
        3. 字段名称可能有变化（如"企业名称"vs"名称"）
        4. 布局相对不规范，需要多种提取策略
        
        Args:
            ocr_results: OCR识别结果列表
            
        Returns:
            BusinessLicenseInfo: 提取的营业执照信息
        """
        info = BusinessLicenseInfo()
        
        # 获取旧版字段映射配置
        field_mapping = self.config["field_mapping"]["old_version"]
        
        # 构建文本位置映射
        text_positions = self._build_text_position_map(ocr_results)
        
        # 合并所有文本用于模式匹配
        all_text = ' '.join([result[1] for result in ocr_results if len(result) > 1])
        
        # 使用多种策略提取字段
        # 策略1: 基于关键词和位置的提取（优先）
        for field_name, keywords in field_mapping.items():
            self.logger.info(f"[老版]提取字段: {field_name}, 关键词: {keywords}")
            extracted_value = self._extract_old_version_field_by_keywords(
                text_positions, keywords, field_name
            )
            self.logger.info(f"[老版]字段 {field_name} 提取原始值: {extracted_value}")

            if extracted_value:
                cleaned_value = self._clean_and_format_field_text(extracted_value, field_name)
                self.logger.info(f"[老版]字段 {field_name} 清理后值: {cleaned_value}")
                if cleaned_value:
                    setattr(info, field_name, cleaned_value)
            else:
                self.logger.info(f"[老版]字段 {field_name} 提取失败")
        
        # 策略2: 基于正则表达式的模式匹配（补充）
        self._extract_old_version_fields_by_patterns(info, all_text)
        
        # 策略3: 特殊字段的精确提取
        self._extract_old_version_special_fields(info, ocr_results, text_positions)
        
        # 策略4: 多模板匹配处理地区差异
        self._apply_regional_templates(info, text_positions, all_text)
        
        return info
    
    def _extract_old_version_field_by_keywords(self, text_positions: List[Dict], 
                                             keywords: List[str], field_name: str) -> Optional[str]:
        """基于关键词提取旧版营业执照字段值
        
        Args:
            text_positions: 文本位置映射
            keywords: 字段关键词列表
            field_name: 字段名称
            
        Returns:
            Optional[str]: 提取的字段值
        """
        # 查找关键词位置
        keyword_positions = []
        for i, text_pos in enumerate(text_positions):
            text = text_pos['text']
            for keyword in keywords:
                if keyword in text:
                    keyword_positions.append({
                        'index': i,
                        'keyword': keyword,
                        'text_pos': text_pos,
                        'keyword_end_x': text_pos['center_x'] + text_pos['width'] / 2
                    })
                    break
        
        if not keyword_positions:
            return None
        
        # 选择最佳的关键词匹配（优先选择完全匹配的关键词）
        best_keyword_pos = self._select_best_keyword_match(keyword_positions, keywords)
        
        # 根据字段类型使用不同的提取策略
        if field_name in ['business_scope']:
            return self._extract_old_version_multiline_field(text_positions, best_keyword_pos)
        elif field_name == 'company_name':
            return self._extract_old_version_company_name(text_positions, best_keyword_pos)
        elif field_name == 'registered_address':
            return self._extract_old_version_address(text_positions, best_keyword_pos)
        else:
            return self._extract_old_version_single_line_field(text_positions, best_keyword_pos)
    
    def _select_best_keyword_match(self, keyword_positions: List[Dict], keywords: List[str]) -> Dict:
        """选择最佳的关键词匹配
        
        Args:
            keyword_positions: 关键词位置列表
            keywords: 原始关键词列表
            
        Returns:
            Dict: 最佳匹配的关键词位置
        """
        if len(keyword_positions) == 1:
            return keyword_positions[0]
        
        # 优先级排序：完全匹配 > 部分匹配 > 置信度高
        def keyword_priority(kp):
            keyword = kp['keyword']
            text = kp['text_pos']['text']
            confidence = kp['text_pos']['confidence']
            
            # 完全匹配得分最高
            if text.strip() == keyword:
                return (3, confidence)
            # 关键词在文本开头
            elif text.startswith(keyword):
                return (2, confidence)
            # 其他情况按置信度排序
            else:
                return (1, confidence)
        
        return max(keyword_positions, key=keyword_priority)
    
    def _extract_old_version_single_line_field(self, text_positions: List[Dict], 
                                             keyword_pos: Dict) -> Optional[str]:
        """提取旧版营业执照单行字段值
        
        Args:
            text_positions: 文本位置映射
            keyword_pos: 关键词位置信息
            
        Returns:
            Optional[str]: 提取的字段值
        """
        keyword_index = keyword_pos['index']
        keyword_text_pos = keyword_pos['text_pos']
        keyword_text = keyword_pos['text_pos']['text']
        keyword = keyword_pos['keyword']
        
        # 策略1: 检查关键词所在文本是否已包含值
        if len(keyword_text) > len(keyword) + 2:
            # 尝试从关键词后提取值
            if ':' in keyword_text or '：' in keyword_text:
                parts = re.split(r'[:：]', keyword_text, 1)
                if len(parts) > 1 and parts[1].strip():
                    return parts[1].strip()
            else:
                # 如果没有冒号，尝试直接提取关键词后的内容
                keyword_end = keyword_text.find(keyword) + len(keyword)
                remaining_text = keyword_text[keyword_end:].strip()
                if remaining_text and len(remaining_text) > 1:
                    return remaining_text
        
        # 策略2: 查找同一行右侧的文本
        same_line_candidates = []
        keyword_end_x = keyword_pos['keyword_end_x']
        
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
                
            # 判断是否在同一行（Y坐标相近）
            y_diff = abs(text_pos['center_y'] - keyword_text_pos['center_y'])
            max_height = max(keyword_text_pos['height'], text_pos['height'])
            
            if y_diff <= max_height * 0.6:  # 旧版允许更大的Y坐标差异
                # 在关键词右侧
                if text_pos['center_x'] > keyword_end_x:
                    same_line_candidates.append(text_pos)
        
        if same_line_candidates:
            # 选择最近的候选文本
            closest_candidate = min(same_line_candidates, 
                                  key=lambda x: x['center_x'] - keyword_end_x)
            return closest_candidate['text']
        
        # 策略3: 查找下一行的文本（旧版布局可能不规整）
        next_line_candidates = []
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
                
            # 判断是否在下一行
            if text_pos['center_y'] > keyword_text_pos['center_y']:
                # 旧版允许更宽松的X坐标匹配
                x_diff = abs(text_pos['center_x'] - keyword_text_pos['center_x'])
                if x_diff <= keyword_text_pos['width'] * 3:  # 更宽松的X坐标限制
                    next_line_candidates.append(text_pos)
                    break  # 只取第一个合适的下一行文本
        
        if next_line_candidates:
            return next_line_candidates[0]['text']
        
        return None
    
    def _extract_old_version_company_name(self, text_positions: List[Dict], 
                                        keyword_pos: Dict) -> Optional[str]:
        """提取旧版营业执照企业名称
        
        旧版企业名称可能跨多行，且格式不统一
        
        Args:
            text_positions: 文本位置映射
            keyword_pos: 关键词位置信息
            
        Returns:
            Optional[str]: 企业名称
        """
        keyword_index = keyword_pos['index']
        keyword_text_pos = keyword_pos['text_pos']
        
        # 收集企业名称的所有部分
        name_parts = []
        
        # 首先检查关键词同一行是否有名称内容
        same_line_text = self._extract_old_version_single_line_field(text_positions, keyword_pos)
        if same_line_text:
            name_parts.append(same_line_text)
        
        # 检查后续行是否有名称的延续
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
            
            # 如果遇到其他字段关键词，停止
            if self._is_old_version_field_keyword(text_pos['text']):
                break
            
            # 如果是名称的延续行
            if (text_pos['center_y'] > keyword_text_pos['center_y'] and
                not self._is_old_version_field_keyword(text_pos['text'])):
                
                # 检查是否可能是企业名称的一部分
                if self._is_likely_company_name_part(text_pos['text']):
                    name_parts.append(text_pos['text'])
                else:
                    # 如果不像企业名称，但距离很近，也可能是名称的一部分
                    y_diff = text_pos['center_y'] - keyword_text_pos['center_y']
                    if y_diff <= keyword_text_pos['height'] * 2:
                        name_parts.append(text_pos['text'])
                    else:
                        break
        
        if name_parts:
            # 合并名称部分，去除多余空格
            full_name = ''.join(name_parts).strip()
            # 清理可能的格式问题
            full_name = re.sub(r'\s+', '', full_name)  # 移除所有空格
            return full_name
        
        return None
    
    def _extract_old_version_address(self, text_positions: List[Dict], 
                                   keyword_pos: Dict) -> Optional[str]:
        """提取旧版营业执照地址信息
        
        地址信息通常较长，可能跨多行
        
        Args:
            text_positions: 文本位置映射
            keyword_pos: 关键词位置信息
            
        Returns:
            Optional[str]: 地址信息
        """
        keyword_index = keyword_pos['index']
        keyword_text_pos = keyword_pos['text_pos']
        
        # 收集地址的所有部分
        address_parts = []
        
        # 首先检查关键词同一行是否有地址内容
        same_line_text = self._extract_old_version_single_line_field(text_positions, keyword_pos)
        if same_line_text:
            address_parts.append(same_line_text)
        
        # 检查后续行是否有地址的延续
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
            
            # 如果遇到其他字段关键词，停止
            if self._is_old_version_field_keyword(text_pos['text']):
                break
            
            # 如果是地址的延续行
            if text_pos['center_y'] > keyword_text_pos['center_y']:
                # 检查是否可能是地址的一部分
                if self._is_likely_address_part(text_pos['text']):
                    address_parts.append(text_pos['text'])
                else:
                    # 如果连续收集了地址内容，遇到不像地址的内容就停止
                    if address_parts:
                        break
        
        if address_parts:
            # 合并地址部分
            full_address = ''.join(address_parts).strip()
            return full_address
        
        return None
    
    def _extract_old_version_multiline_field(self, text_positions: List[Dict], 
                                           keyword_pos: Dict) -> Optional[str]:
        """提取旧版营业执照多行字段（如经营范围）
        
        Args:
            text_positions: 文本位置映射
            keyword_pos: 关键词位置信息
            
        Returns:
            Optional[str]: 多行字段值
        """
        keyword_index = keyword_pos['index']
        keyword_text_pos = keyword_pos['text_pos']
        
        # 收集字段的所有文本
        field_texts = []
        
        # 首先检查同一行是否有内容
        same_line_text = self._extract_old_version_single_line_field(text_positions, keyword_pos)
        if same_line_text:
            field_texts.append(same_line_text)
        
        # 然后收集后续行的内容
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
            
            # 跳过已经作为同一行内容收集的文本
            if same_line_text and text_pos['text'] == same_line_text:
                continue
            
            # 如果遇到其他字段的关键词，停止收集
            if self._is_old_version_field_keyword(text_pos['text']):
                break
            
            # 收集位置合理的文本（在关键词下方）
            if text_pos['center_y'] > keyword_text_pos['center_y']:
                field_texts.append(text_pos['text'])
        
        if field_texts:
            return ' '.join(field_texts)
        
        return None
    
    def _is_old_version_field_keyword(self, text: str) -> bool:
        """判断文本是否为旧版营业执照字段关键词
        
        Args:
            text: 文本内容
            
        Returns:
            bool: 是否为字段关键词
        """
        all_keywords = []
        for field_keywords in self.config["field_mapping"]["old_version"].values():
            all_keywords.extend(field_keywords)
        
        # 添加一些旧版特有的关键词
        additional_keywords = ['经济性质', '经营方式', '经营期限', '发证日期', '年检情况']
        all_keywords.extend(additional_keywords)
        
        for keyword in all_keywords:
            if keyword in text:
                return True
        
        return False
    
    def _is_likely_address_part(self, text: str) -> bool:
        """判断文本是否可能是地址的一部分
        
        Args:
            text: 文本内容
            
        Returns:
            bool: 是否可能是地址的一部分
        """
        # 地址通常包含的词汇
        address_indicators = [
            '省', '市', '区', '县', '街道', '路', '号', '楼', '室', '层',
            '镇', '乡', '村', '组', '弄', '巷', '里', '段', '栋', '单元'
        ]
        
        for indicator in address_indicators:
            if indicator in text:
                return True
        
        # 如果包含数字和中文字符，也可能是地址的一部分
        if re.search(r'\d', text) and re.search(r'[\u4e00-\u9fff]', text):
            return True
        
        return False
    
    def _extract_old_version_fields_by_patterns(self, info: BusinessLicenseInfo, all_text: str):
        """基于正则表达式模式匹配提取旧版字段（补充策略）
        
        Args:
            info: 营业执照信息对象
            all_text: 所有OCR文本
        """
        # 定义旧版营业执照的字段提取模式
        patterns = {
            'registration_number': [
                r'注册号\s*[:：]?\s*(\d{15})',
                r'注册号码\s*[:：]?\s*(\d{15})',
                r'工商注册号\s*[:：]?\s*(\d{15})',
                r'(\d{15})',  # 直接匹配15位数字
            ],
            'company_name': [
                r'企业名称\s*[:：]?\s*([^\n\r]+?)(?=\s*企业类型|\s*注册号|\s*法定代表人)',
                r'名\s*称\s*[:：]?\s*([^\n\r]+?)(?=\s*类型|\s*注册号)',
                r'单位名称\s*[:：]?\s*([^\n\r]+?)(?=\s*类型|\s*注册号)',
            ],
            'legal_representative': [
                r'法定代表人\s*[:：]?\s*([^\n\r\s]+)',
                r'法人代表\s*[:：]?\s*([^\n\r\s]+)',
                r'负责人\s*[:：]?\s*([^\n\r\s]+)',
            ],
            'registered_capital': [
                r'注册资本\s*[:：]?\s*([^\n\r]+?)(?=\s*成立日期|\s*营业期限)',
                r'资本总额\s*[:：]?\s*([^\n\r]+?)(?=\s*成立日期|\s*营业期限)',
            ],
            'establishment_date': [
                r'成立日期\s*[:：]?\s*(\d{4}年\d{1,2}月\d{1,2}日)',
                r'成立时间\s*[:：]?\s*(\d{4}年\d{1,2}月\d{1,2}日)',
                r'开业日期\s*[:：]?\s*(\d{4}年\d{1,2}月\d{1,2}日)',
            ],
            'company_type': [
                r'企业类型\s*[:：]?\s*([^\n\r]+?)(?=\s*法定代表人|\s*企业住所)',
                r'经济性质\s*[:：]?\s*([^\n\r]+?)(?=\s*法定代表人|\s*企业住所)',
                r'类\s*型\s*[:：]?\s*([^\n\r]+?)(?=\s*法定代表人|\s*住所)',
            ],
            'registered_address': [
                r'企业住所\s*[:：]?\s*([^\n\r]+?)(?=\s*经营范围|\s*登记机关|$)',
                r'住\s*所\s*[:：]?\s*([^\n\r]+?)(?=\s*经营范围|\s*登记机关|$)',
                r'地\s*址\s*[:：]?\s*([^\n\r]+?)(?=\s*经营范围|\s*登记机关|$)',
            ],
            'registration_authority': [
                r'登记机关\s*[:：]?\s*([^\n\r]+?)(?=\s*核准日期|$)',
                r'发证机关\s*[:：]?\s*([^\n\r]+?)(?=\s*核准日期|$)',
            ],
            'approval_date': [
                r'核准日期\s*[:：]?\s*(\d{4}年\d{1,2}月\d{1,2}日)',
                r'发证日期\s*[:：]?\s*(\d{4}年\d{1,2}月\d{1,2}日)',
                r'颁发日期\s*[:：]?\s*(\d{4}年\d{1,2}月\d{1,2}日)',
            ]
        }
        
        # 只对尚未提取到的字段进行模式匹配
        for field_name, field_patterns in patterns.items():
            current_value = getattr(info, field_name, None)
            if current_value:  # 如果已经有值，跳过
                continue
                
            for pattern in field_patterns:
                match = re.search(pattern, all_text, re.DOTALL | re.IGNORECASE)
                if match:
                    value = match.group(1).strip()
                    if value:
                        # 对注册号进行特殊验证
                        if field_name == 'registration_number':
                            validation = BusinessLicenseValidator.validate_registration_number(value)
                            if validation['valid']:
                                setattr(info, field_name, validation['formatted_number'])
                                break
                        else:
                            cleaned_value = self._clean_and_format_field_text(value, field_name)
                            if cleaned_value:
                                setattr(info, field_name, cleaned_value)
                                break
    
    def _extract_old_version_special_fields(self, info: BusinessLicenseInfo, 
                                          ocr_results: List[Tuple], 
                                          text_positions: List[Dict]):
        """提取旧版营业执照特殊字段
        
        Args:
            info: 营业执照信息对象
            ocr_results: OCR识别结果
            text_positions: 文本位置映射
        """
        # 精确提取注册号
        if not info.registration_number:
            info.registration_number = self._extract_registration_number_precise(ocr_results)
        
        # 精确提取经营范围（旧版经营范围通常很长）
        if not info.business_scope:
            info.business_scope = self._extract_old_version_business_scope_precise(text_positions)

        # 精确提取成立日期（处理被拆分的情况）
        if not info.establishment_date:
            info.establishment_date = self._extract_old_version_date_from_fragments(text_positions, ['成立', '成'])

        # 精确提取营业期限
        if not info.business_term:
            info.business_term = self._extract_old_version_date_from_fragments(text_positions, ['期限', '期'])

        # 精确提取住所地址
        if not info.registered_address:
            info.registered_address = self._extract_old_version_address_precise(text_positions)
    
    def _extract_registration_number_precise(self, ocr_results: List[Tuple]) -> Optional[str]:
        """精确提取注册号
        
        Args:
            ocr_results: OCR识别结果
            
        Returns:
            Optional[str]: 注册号
        """
        # 首先尝试直接从OCR结果中找到15位数字
        for bbox, text, confidence in ocr_results:
            # 清理文本，只保留数字
            cleaned_text = re.sub(r'[^\d]', '', text)
            
            # 检查是否为15位数字
            if len(cleaned_text) == 15 and cleaned_text.isdigit():
                validation = BusinessLicenseValidator.validate_registration_number(cleaned_text)
                if validation['valid']:
                    return validation['formatted_number']
        
        # 合并所有文本进行模式匹配
        all_text = ' '.join([result[1] for result in ocr_results if len(result) > 1])
        
        # 使用正则表达式精确匹配15位数字
        reg_number_pattern = self.config["version_detection"]["registration_number_pattern"]
        matches = re.findall(reg_number_pattern, all_text)
        
        if matches:
            # 验证找到的注册号
            for number in matches:
                validation = BusinessLicenseValidator.validate_registration_number(number)
                if validation['valid']:
                    return validation['formatted_number']
        
        # 如果精确匹配失败，尝试模糊匹配
        return self._extract_registration_number_fuzzy(all_text)
    
    def _extract_registration_number_fuzzy(self, text: str) -> Optional[str]:
        """模糊匹配注册号
        
        Args:
            text: 文本内容
            
        Returns:
            Optional[str]: 注册号
        """
        # 查找可能的15位数字（允许一些OCR错误）
        potential_numbers = re.findall(r'\d{13,17}', text)
        
        for number in potential_numbers:
            if len(number) == 15:
                validation = BusinessLicenseValidator.validate_registration_number(number)
                if validation['valid']:
                    return validation['formatted_number']
        
        return None
    
    def _extract_old_version_business_scope_precise(self, text_positions: List[Dict]) -> Optional[str]:
        """精确提取旧版营业执照经营范围
        
        Args:
            text_positions: 文本位置映射
            
        Returns:
            Optional[str]: 经营范围
        """
        # 查找"经营范围"关键词
        scope_keyword_pos = None
        for i, text_pos in enumerate(text_positions):
            if '经营范围' in text_pos['text']:
                scope_keyword_pos = {
                    'index': i,
                    'text_pos': text_pos
                }
                break
        
        if not scope_keyword_pos:
            return None
        
        # 收集经营范围的所有文本
        scope_texts = []
        keyword_index = scope_keyword_pos['index']
        keyword_text_pos = scope_keyword_pos['text_pos']
        
        # 首先检查关键词同一行是否有内容
        keyword_text = keyword_text_pos['text']
        if '经营范围' in keyword_text and len(keyword_text) > 4:
            # 提取关键词后的内容
            scope_start = keyword_text.find('经营范围') + 4
            if scope_start < len(keyword_text):
                remaining = keyword_text[scope_start:].strip()
                if remaining.startswith(':') or remaining.startswith('：'):
                    remaining = remaining[1:].strip()
                if remaining:
                    scope_texts.append(remaining)
        
        # 收集后续行的经营范围内容
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
            
            # 如果遇到其他字段关键词，停止收集
            if self._is_old_version_field_keyword(text_pos['text']) and '经营范围' not in text_pos['text']:
                break
            
            # 收集经营范围相关的文本
            if text_pos['center_y'] > keyword_text_pos['center_y']:
                scope_texts.append(text_pos['text'])
        
        if scope_texts:
            # 合并文本，用分号分隔不同行
            return '; '.join(scope_texts)
        
        return None
    
    def _apply_regional_templates(self, info: BusinessLicenseInfo, 
                                text_positions: List[Dict], all_text: str):
        """应用地区模板处理版式差异
        
        不同地区的旧版营业执照可能有不同的版式和字段名称
        
        Args:
            info: 营业执照信息对象
            text_positions: 文本位置映射
            all_text: 所有OCR文本
        """
        # 检测可能的地区特征
        region_indicators = {
            'beijing': ['北京', '京'],
            'shanghai': ['上海', '沪'],
            'guangdong': ['广东', '粤'],
            'jiangsu': ['江苏', '苏'],
            'zhejiang': ['浙江', '浙'],
            'shandong': ['山东', '鲁'],
        }
        
        detected_region = None
        for region, indicators in region_indicators.items():
            for indicator in indicators:
                if indicator in all_text:
                    detected_region = region
                    break
            if detected_region:
                break
        
        # 根据检测到的地区应用特殊处理
        if detected_region:
            self._apply_region_specific_extraction(info, text_positions, all_text, detected_region)
    
    def _apply_region_specific_extraction(self, info: BusinessLicenseInfo, 
                                        text_positions: List[Dict], 
                                        all_text: str, region: str):
        """应用地区特定的提取规则
        
        Args:
            info: 营业执照信息对象
            text_positions: 文本位置映射
            all_text: 所有OCR文本
            region: 检测到的地区
        """
        # 地区特定的字段名称变体
        region_field_variants = {
            'beijing': {
                'company_name': ['企业名称', '单位名称'],
                'company_type': ['企业类型', '经济性质', '经济类型'],
            },
            'shanghai': {
                'registered_address': ['企业住所', '住所', '地址'],
                'registration_authority': ['登记机关', '发证机关', '核发机关'],
            },
            'guangdong': {
                'legal_representative': ['法定代表人', '法人代表', '企业负责人'],
            }
        }
        
        # 应用地区特定的字段变体
        if region in region_field_variants:
            variants = region_field_variants[region]
            for field_name, field_variants in variants.items():
                current_value = getattr(info, field_name, None)
                if not current_value:  # 只对未提取到的字段应用地区变体
                    for variant in field_variants:
                        # 使用变体关键词重新提取
                        extracted_value = self._extract_field_by_variant_keyword(
                            text_positions, variant, field_name
                        )
                        if extracted_value:
                            cleaned_value = self._clean_and_format_field_text(extracted_value, field_name)
                            if cleaned_value:
                                setattr(info, field_name, cleaned_value)
                                break
    
    def _extract_field_by_variant_keyword(self, text_positions: List[Dict], 
                                        keyword: str, field_name: str) -> Optional[str]:
        """使用变体关键词提取字段
        
        Args:
            text_positions: 文本位置映射
            keyword: 变体关键词
            field_name: 字段名称
            
        Returns:
            Optional[str]: 提取的字段值
        """
        # 查找变体关键词
        for i, text_pos in enumerate(text_positions):
            if keyword in text_pos['text']:
                keyword_pos = {
                    'index': i,
                    'keyword': keyword,
                    'text_pos': text_pos,
                    'keyword_end_x': text_pos['center_x'] + text_pos['width'] / 2
                }
                
                # 使用标准的单行字段提取方法
                return self._extract_old_version_single_line_field(text_positions, keyword_pos)
        
        return None
    
    def _build_text_position_map(self, ocr_results: List[Tuple]) -> List[Dict]:
        """构建文本位置映射
        
        Args:
            ocr_results: OCR识别结果
            
        Returns:
            List[Dict]: 包含文本、位置和置信度的字典列表
        """
        text_positions = []
        
        for bbox, text, confidence in ocr_results:
            if bbox and len(bbox) == 4:
                # 计算文本框的中心点和区域
                x_coords = [point[0] for point in bbox]
                y_coords = [point[1] for point in bbox]
                
                center_x = sum(x_coords) / 4
                center_y = sum(y_coords) / 4
                width = max(x_coords) - min(x_coords)
                height = max(y_coords) - min(y_coords)
                
                text_positions.append({
                    'text': text,
                    'bbox': bbox,
                    'center_x': center_x,
                    'center_y': center_y,
                    'width': width,
                    'height': height,
                    'confidence': confidence
                })
        
        # 按从上到下、从左到右的顺序排序
        text_positions.sort(key=lambda x: (x['center_y'], x['center_x']))
        
        return text_positions
    
    def _extract_field_by_keywords_and_position(self, text_positions: List[Dict],
                                               keywords: List[str], field_name: str) -> Optional[str]:
        """基于关键词和位置提取字段值 - 新版营业执照优化版

        Args:
            text_positions: 文本位置映射
            keywords: 字段关键词列表
            field_name: 字段名称

        Returns:
            Optional[str]: 提取的字段值
        """
        # 针对新版营业执照的专门优化策略
        if field_name == 'company_name':
            return self._extract_company_name_optimized(text_positions)
        elif field_name == 'unified_social_credit_code':
            return self._extract_unified_social_credit_code_optimized(text_positions, keywords)
        elif field_name == 'legal_representative':
            return self._extract_legal_representative_optimized(text_positions)
        elif field_name == 'registered_capital':
            return self._extract_registered_capital_optimized(text_positions)
        elif field_name == 'establishment_date':
            return self._extract_establishment_date_optimized(text_positions)
        elif field_name == 'business_term':
            return self._extract_business_term_optimized(text_positions)
        elif field_name == 'business_scope':
            return self._extract_business_scope_optimized(text_positions)
        elif field_name == 'company_type':
            return self._extract_company_type_optimized(text_positions)
        elif field_name == 'registered_address':
            return self._extract_registered_address_optimized(text_positions)
        elif field_name == 'registration_authority':
            return self._extract_registration_authority_optimized(text_positions)

        # 通用匹配逻辑（保留）
        keyword_positions = []
        for i, text_pos in enumerate(text_positions):
            text = text_pos['text']
            for keyword in keywords:
                if keyword in text:
                    keyword_positions.append({
                        'index': i,
                        'keyword': keyword,
                        'text_pos': text_pos,
                        'keyword_end_x': text_pos['center_x'] + text_pos['width'] / 2
                    })
                    break
        
        if not keyword_positions:
            return None
        
        # 选择最佳的关键词匹配
        best_keyword_pos = max(keyword_positions, key=lambda x: x['text_pos']['confidence'])
        
        # 根据字段类型使用不同的提取策略
        if field_name in ['business_scope']:
            return self._extract_multiline_field_value(text_positions, best_keyword_pos)
        else:
            return self._extract_single_line_field_value(text_positions, best_keyword_pos)
    
    def _extract_single_line_field_value(self, text_positions: List[Dict],
                                        keyword_pos: Dict) -> Optional[str]:
        """提取单行字段值

        Args:
            text_positions: 文本位置映射
            keyword_pos: 关键词位置信息

        Returns:
            Optional[str]: 提取的字段值
        """
        keyword_index = keyword_pos['index']
        keyword_text_pos = keyword_pos['text_pos']
        keyword_end_x = keyword_pos['keyword_end_x']
        keyword_text = keyword_text_pos['text']

        # 策略0: 检查关键词文本本身是否包含值（如统一社会信用代码）
        keyword = keyword_pos['keyword']
        if keyword in keyword_text:
            # 特殊处理统一社会信用代码
            if keyword == '统一社会信用代码':
                # 直接寻找18位代码模式
                credit_code_pattern = r'([0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10})'
                matches = re.findall(credit_code_pattern, keyword_text)
                if matches:
                    self.logger.info(f"从关键词文本中提取统一社会信用代码: {matches[0]}")
                    return matches[0]

                # 移除关键词，提取剩余的代码部分
                remaining_text = keyword_text.replace(keyword, '').strip()
                if len(remaining_text) == 18 and re.match(r'^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$', remaining_text):
                    self.logger.info(f"从关键词文本中提取统一社会信用代码: {remaining_text}")
                    return remaining_text
            else:
                # 尝试从关键词文本中提取值
                remaining_text = keyword_text.replace(keyword, '').strip()
                if remaining_text:
                    self.logger.info(f"从关键词文本中提取值: {remaining_text}")
                    return remaining_text

        # 策略1: 查找同一行右侧的文本
        same_line_candidates = []
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue

            # 判断是否在同一行（Y坐标相近）
            y_diff = abs(text_pos['center_y'] - keyword_text_pos['center_y'])
            if y_diff <= max(keyword_text_pos['height'], text_pos['height']) * 0.5:
                # 在关键词右侧
                if text_pos['center_x'] > keyword_end_x:
                    same_line_candidates.append(text_pos)
        
        if same_line_candidates:
            # 选择最近的候选文本
            closest_candidate = min(same_line_candidates, 
                                  key=lambda x: x['center_x'] - keyword_end_x)
            return closest_candidate['text']
        
        # 策略2: 查找下一行的文本
        next_line_candidates = []
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
                
            # 判断是否在下一行
            if text_pos['center_y'] > keyword_text_pos['center_y']:
                # 检查X坐标是否合理（不要太偏左或太偏右）
                x_diff = abs(text_pos['center_x'] - keyword_text_pos['center_x'])
                if x_diff <= keyword_text_pos['width'] * 2:
                    next_line_candidates.append(text_pos)
                    break  # 只取第一个合适的下一行文本
        
        if next_line_candidates:
            return next_line_candidates[0]['text']
        
        return None
    
    def _extract_multiline_field_value(self, text_positions: List[Dict], 
                                      keyword_pos: Dict) -> Optional[str]:
        """提取多行字段值（如经营范围）
        
        Args:
            text_positions: 文本位置映射
            keyword_pos: 关键词位置信息
            
        Returns:
            Optional[str]: 提取的多行字段值
        """
        keyword_index = keyword_pos['index']
        keyword_text_pos = keyword_pos['text_pos']
        
        # 收集关键词后面的所有相关文本
        field_texts = []
        
        # 首先检查同一行是否有内容
        same_line_text = self._extract_single_line_field_value(text_positions, keyword_pos)
        if same_line_text:
            field_texts.append(same_line_text)
        
        # 然后收集后续行的内容
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
            
            # 跳过已经作为同一行内容收集的文本
            if same_line_text and text_pos['text'] == same_line_text:
                continue
            
            # 如果遇到其他字段的关键词，停止收集
            if self._is_field_keyword(text_pos['text']):
                break
            
            # 收集位置合理的文本（在关键词下方）
            if text_pos['center_y'] > keyword_text_pos['center_y']:
                field_texts.append(text_pos['text'])
        
        if field_texts:
            return ' '.join(field_texts)
        
        return None
    
    def _is_field_keyword(self, text: str) -> bool:
        """判断文本是否为字段关键词
        
        Args:
            text: 文本内容
            
        Returns:
            bool: 是否为字段关键词
        """
        all_keywords = []
        for field_keywords in self.config["field_mapping"]["new_version"].values():
            all_keywords.extend(field_keywords)
        
        for keyword in all_keywords:
            if keyword in text:
                return True
        
        return False
    
    def _extract_credit_code_precise(self, ocr_results: List[Tuple]) -> Optional[str]:
        """精确提取统一社会信用代码
        
        Args:
            ocr_results: OCR识别结果
            
        Returns:
            Optional[str]: 统一社会信用代码
        """
        # 首先尝试直接从OCR结果中找到18位代码
        for bbox, text, confidence in ocr_results:
            # 清理文本，移除空格和特殊字符
            cleaned_text = re.sub(r'[^\w]', '', text.upper())
            
            # 检查是否为18位统一社会信用代码格式
            if len(cleaned_text) == 18 and re.match(r'^[0-9A-HJ-NPQRTUWXY]{18}$', cleaned_text):
                validation = BusinessLicenseValidator.validate_unified_social_credit_code(cleaned_text)
                if validation['valid']:
                    return validation['formatted_code']
        
        # 合并所有文本进行模式匹配
        all_text = ' '.join([result[1] for result in ocr_results if len(result) > 1])
        
        # 使用正则表达式精确匹配18位统一社会信用代码
        credit_code_pattern = self.config["version_detection"]["credit_code_pattern"]
        matches = re.findall(credit_code_pattern, all_text)
        
        if matches:
            # 验证找到的代码
            for code in matches:
                validation = BusinessLicenseValidator.validate_unified_social_credit_code(code)
                if validation['valid']:
                    return validation['formatted_code']
        
        # 如果精确匹配失败，尝试模糊匹配
        return self._extract_credit_code_fuzzy(all_text)
    
    def _extract_credit_code_fuzzy(self, text: str) -> Optional[str]:
        """模糊匹配统一社会信用代码
        
        Args:
            text: 文本内容
            
        Returns:
            Optional[str]: 统一社会信用代码
        """
        # 查找可能的18位代码（允许一些OCR错误字符）
        # 扩展字符集以包含常见的OCR错误字符
        potential_codes = re.findall(r'[0-9A-HJ-NPQRTUWXYIOZS]{16,20}', text)
        
        for code in potential_codes:
            if len(code) == 18:
                # 尝试修正常见的OCR错误
                corrected_code = self._correct_credit_code_ocr_errors(code)
                validation = BusinessLicenseValidator.validate_unified_social_credit_code(corrected_code)
                if validation['valid']:
                    return validation['formatted_code']
        
        # 如果上述方法失败，尝试更宽松的匹配
        # 查找任何18位的字母数字组合
        loose_codes = re.findall(r'[0-9A-Z]{18}', text)
        for code in loose_codes:
            corrected_code = self._correct_credit_code_ocr_errors(code)
            validation = BusinessLicenseValidator.validate_unified_social_credit_code(corrected_code)
            if validation['valid']:
                return validation['formatted_code']
        
        return None
    
    def _correct_credit_code_ocr_errors(self, code: str) -> str:
        """修正统一社会信用代码的常见OCR错误
        
        Args:
            code: 原始代码
            
        Returns:
            str: 修正后的代码
        """
        # 常见OCR错误映射（注意方向：错误->正确）
        ocr_corrections = {
            'I': '1',  # I容易被误识别，应该是1
            'O': '0',  # O容易被误识别，应该是0
            'Z': '2',  # Z容易被误识别，应该是2
            'S': '5',  # S容易被误识别，应该是5
            'B': '8',  # B容易被误识别，应该是8
            'G': '6',  # G容易被误识别，应该是6
        }
        
        corrected = code
        for wrong, correct in ocr_corrections.items():
            corrected = corrected.replace(wrong, correct)
        
        return corrected
    
    def _extract_company_name_precise(self, ocr_results: List[Tuple]) -> Optional[str]:
        """精确提取企业名称
        
        Args:
            ocr_results: OCR识别结果
            
        Returns:
            Optional[str]: 企业名称
        """
        text_positions = self._build_text_position_map(ocr_results)
        
        # 查找"名称"关键词
        name_keyword_pos = None
        for i, text_pos in enumerate(text_positions):
            if '名称' in text_pos['text']:
                name_keyword_pos = {
                    'index': i,
                    'text_pos': text_pos,
                    'keyword_end_x': text_pos['center_x'] + text_pos['width'] / 2
                }
                break
        
        if not name_keyword_pos:
            return None
        
        # 提取企业名称（可能跨多行）
        company_name_parts = []
        keyword_index = name_keyword_pos['index']
        keyword_text_pos = name_keyword_pos['text_pos']
        
        # 检查同一行是否有名称内容
        same_line_text = self._extract_single_line_field_value(text_positions, name_keyword_pos)
        if same_line_text:
            company_name_parts.append(same_line_text)
        
        # 检查下面几行是否有名称的延续
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
            
            # 如果遇到其他字段关键词，停止
            if self._is_field_keyword(text_pos['text']) and '名称' not in text_pos['text']:
                break
            
            # 如果是名称的延续行
            if (text_pos['center_y'] > keyword_text_pos['center_y'] and
                not self._is_field_keyword(text_pos['text'])):
                
                # 检查是否可能是企业名称的一部分
                if self._is_likely_company_name_part(text_pos['text']):
                    company_name_parts.append(text_pos['text'])
                else:
                    break
        
        if company_name_parts:
            return ''.join(company_name_parts)
        
        return None
    
    def _is_likely_company_name_part(self, text: str) -> bool:
        """判断文本是否可能是企业名称的一部分
        
        Args:
            text: 文本内容
            
        Returns:
            bool: 是否可能是企业名称的一部分
        """
        # 企业名称通常包含的词汇
        company_indicators = ['公司', '企业', '集团', '有限', '股份', '责任', '科技', '贸易', '投资', '发展']
        
        for indicator in company_indicators:
            if indicator in text:
                return True
        
        # 如果包含中文字符且长度合理，也可能是企业名称的一部分
        if re.search(r'[\u4e00-\u9fff]', text) and 2 <= len(text) <= 20:
            return True
        
        return False
    
    def _extract_business_scope_multiline(self, ocr_results: List[Tuple]) -> Optional[str]:
        """提取多行经营范围
        
        Args:
            ocr_results: OCR识别结果
            
        Returns:
            Optional[str]: 经营范围
        """
        text_positions = self._build_text_position_map(ocr_results)
        
        # 查找"经营范围"关键词
        scope_keyword_pos = None
        for i, text_pos in enumerate(text_positions):
            if '经营范围' in text_pos['text']:
                scope_keyword_pos = {
                    'index': i,
                    'text_pos': text_pos
                }
                break
        
        if not scope_keyword_pos:
            return None
        
        # 收集经营范围的所有文本
        scope_texts = []
        keyword_index = scope_keyword_pos['index']
        keyword_text_pos = scope_keyword_pos['text_pos']
        
        for i, text_pos in enumerate(text_positions):
            if i <= keyword_index:
                continue
            
            # 如果遇到其他字段关键词，停止收集
            if self._is_field_keyword(text_pos['text']) and '经营范围' not in text_pos['text']:
                break
            
            # 收集经营范围相关的文本
            if text_pos['center_y'] > keyword_text_pos['center_y']:
                scope_texts.append(text_pos['text'])
        
        if scope_texts:
            # 合并文本，用分号分隔不同行
            return '; '.join(scope_texts)
        
        return None
    
    def _clean_and_format_field_text(self, text: str, field_name: str) -> str:
        """清理和格式化字段文本
        
        Args:
            text: 原始文本
            field_name: 字段名称
            
        Returns:
            str: 清理后的文本
        """
        if not text:
            return ""
        
        # 基础清理
        cleaned_text = self._clean_text(text)
        
        # 根据字段类型进行特殊处理
        if field_name == 'unified_social_credit_code':
            # 统一社会信用代码：移除所有空格和特殊字符
            cleaned_text = re.sub(r'[^\w]', '', cleaned_text.upper())
        elif field_name == 'registered_capital':
            # 注册资本：保留数字、中文和常用符号
            cleaned_text = re.sub(r'[^\u4e00-\u9fff\d\.\,万千百十亿元人民币美元]', '', cleaned_text)
        elif field_name == 'legal_representative':
            # 法定代表人：移除常见前缀词
            prefixes_to_remove = ['法定代表人', '姓名', '代表人', '负责人']
            for prefix in prefixes_to_remove:
                if cleaned_text.startswith(prefix):
                    cleaned_text = cleaned_text[len(prefix):].strip()
                    break
        elif field_name == 'company_name':
            # 公司名称：移除常见前缀词
            prefixes_to_remove = ['企业名称', '名称', '称', '名']
            for prefix in prefixes_to_remove:
                if cleaned_text.startswith(prefix):
                    cleaned_text = cleaned_text[len(prefix):].strip()
                    break
        elif field_name in ['establishment_date', 'approval_date']:
            # 日期：标准化日期格式
            cleaned_text = self._normalize_date_format(cleaned_text)
        elif field_name == 'business_scope':
            # 经营范围：保留更多标点符号
            cleaned_text = re.sub(r'[^\u4e00-\u9fff\w\-\.\(\),;:、，。；：]', '', cleaned_text)
        
        return cleaned_text.strip()
    
    def _normalize_date_format(self, date_text: str) -> str:
        """标准化日期格式
        
        Args:
            date_text: 原始日期文本
            
        Returns:
            str: 标准化后的日期文本
        """
        # 尝试提取日期信息
        date_patterns = [
            r'(\d{4})年(\d{1,2})月(\d{1,2})日',
            r'(\d{4})-(\d{2})-(\d{2})',
            r'(\d{4})/(\d{2})/(\d{2})',
            r'(\d{4})\.(\d{2})\.(\d{2})'
        ]
        
        for pattern in date_patterns:
            match = re.search(pattern, date_text)
            if match:
                year, month, day = match.groups()
                return f"{year}年{month.zfill(2)}月{day.zfill(2)}日"
        
        return date_text
    
    def _clean_text(self, text: str) -> str:
        """清理文本
        
        Args:
            text (str): 需要清理的文本
            
        Returns:
            str: 清理后的文本
        """
        if not text:
            return ""
        
        # 应用配置中的文本清理规则
        text_cleaning = self.config.get("text_cleaning", {})
        
        # 移除特殊符号
        remove_patterns = text_cleaning.get("remove_patterns", [])
        for pattern in remove_patterns:
            text = text.replace(pattern, '')
        
        # 标准化符号
        normalize_patterns = text_cleaning.get("normalize_patterns", {})
        for old_char, new_char in normalize_patterns.items():
            text = text.replace(old_char, new_char)
        
        # 移除多余的空白字符
        text = re.sub(r'\s+', ' ', text).strip()

        return text

    def _extract_company_name_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的公司名称提取 - 新版V2"""
        # 策略1: 从包含"称"字的文本中提取公司名称（新版营业执照专用）
        for text_pos in text_positions:
            text = text_pos['text'].strip()
            if '称' in text and ('公司' in text or '企业' in text):
                # 使用正则提取公司名称，移除"称"字前缀
                company_pattern = r'称?([^。]{2,30}(?:公司|企业|集团|有限责任公司|股份有限公司))'
                matches = re.findall(company_pattern, text)
                if matches:
                    company_name = matches[0].strip()
                    if len(company_name) > 3:
                        self.logger.info(f"从称字段提取公司名称: {company_name}")
                        return company_name

        # 策略2: 寻找完整的公司名称文本块（新旧版本通用）
        for text_pos in text_positions:
            text = text_pos['text'].strip()
            # 如果文本包含公司关键词且不包含干扰词
            if (any(keyword in text for keyword in ['公司', '企业', '集团']) and
                not any(disturb in text for disturb in ['经营范围', '范围', '称', '型', '所', '注册', '成立']) and
                len(text) > 6):  # 公司名称通常比较长
                self.logger.info(f"找到完整公司名称: {text}")
                return text

        # 策略3: 原有逻辑作为兜底
        # 基于OCR分析：公司名称在"称"字段附近
        for i, text_pos in enumerate(text_positions):
            text = text_pos['text']
            if '称' in text:
                # 查找同一行右侧或下一个文本块
                for j in range(i + 1, len(text_positions)):
                    next_text = text_positions[j]['text']
                    # 如果包含公司关键词，很可能是公司名称
                    if any(keyword in next_text for keyword in ['公司', '企业', '集团', '有限', '股份']):
                        self.logger.info(f"找到公司名称: {next_text}")
                        return next_text

        # 直接搜索包含公司关键词的文本
        for text_pos in text_positions:
            text = text_pos['text']
            if '公司' in text and len(text) > 3:
                self.logger.info(f"直接匹配公司名称: {text}")
                return text

        return None

    def _extract_legal_representative_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的法定代表人提取"""
        for i, text_pos in enumerate(text_positions):
            text = text_pos['text']
            if '法定代表人' in text:
                # 先尝试从同一文本块中提取人名
                person_pattern = r'法定代表人([\u4e00-\u9fff]{2,4})'
                matches = re.findall(person_pattern, text)
                if matches:
                    person_name = matches[0].strip()
                    self.logger.info(f"V2从同一文本块提取法定代表人: {person_name}")
                    return person_name

                # 查找同一行右侧或下一个文本块
                for j in range(i + 1, min(i + 5, len(text_positions))):
                    next_text = text_positions[j]['text'].strip()
                    # 如果是人名（中文字符且长度合理）且不包含数字或特殊符号
                    if (re.match(r'^[\u4e00-\u9fff]{2,4}$', next_text) and
                        not any(char in next_text for char in ['万', '元', '资', '本', '年', '月', '日'])):
                        self.logger.info(f"找到法定代表人: {next_text}")
                        return next_text

        # 如果第一种方法失败，直接搜索可能的人名（严格过滤）
        for text_pos in text_positions:
            text = text_pos['text'].strip()
            if (re.match(r'^[\u4e00-\u9fff]{2,4}$', text) and
                not any(keyword in text for keyword in [
                    '公司', '企业', '地址', '代码', '号', '年', '月', '日', '万', '元', '资', '本',
                    '营业', '执照', '类', '住', '称', '型', '所', '注', '册', '成', '立', '期', '限',
                    '经', '营', '登记', '机关', '核准', '统一', '社会', '信用'
                ])):
                # 进一步验证：检查附近是否有"法定代表人"
                for other_pos in text_positions:
                    if '法定代表人' in other_pos['text']:
                        self.logger.info(f"通过严格人名模式找到法定代表人: {text}")
                        return text
        return None

    def _extract_registered_capital_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的注册资本提取"""
        # 基于OCR分析：寻找包含"万元"或资本金额的文本
        for text_pos in text_positions:
            text = text_pos['text']
            if '万元' in text or '元整' in text:
                self.logger.info(f"找到注册资本: {text}")
                return text

        # 寻找"注册资本"关键词附近的文本
        for i, text_pos in enumerate(text_positions):
            text = text_pos['text']
            if '资本' in text:
                for j in range(i + 1, min(i + 3, len(text_positions))):
                    next_text = text_positions[j]['text']
                    if '万' in next_text or '元' in next_text:
                        self.logger.info(f"通过关键词找到注册资本: {next_text}")
                        return next_text
        return None

    def _extract_establishment_date_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的成立日期提取"""
        # 寻找日期格式的文本
        date_pattern = r'\d{4}年\d{1,2}月\d{1,2}日'
        for text_pos in text_positions:
            text = text_pos['text']
            if re.search(date_pattern, text) and '至' not in text:
                self.logger.info(f"找到成立日期: {text}")
                return text
        return None

    def _extract_business_term_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的营业期限提取"""
        # 寻找包含"至"或"长期"的日期文本
        for text_pos in text_positions:
            text = text_pos['text']
            if ('至' in text or '长期' in text) and '年' in text:
                self.logger.info(f"找到营业期限: {text}")
                return text
        return None

    def _extract_business_scope_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的经营范围提取"""
        # 寻找包含业务关键词的长文本
        scope_texts = []
        for text_pos in text_positions:
            text = text_pos['text']
            if (('服务' in text or '经营' in text or '技术' in text or '软件' in text) and
                len(text) > 10):
                scope_texts.append(text)

        if scope_texts:
            combined_scope = '。'.join(scope_texts)
            self.logger.info(f"找到经营范围: {combined_scope}")
            return combined_scope
        return None

    def _extract_company_type_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的公司类型提取"""
        # 寻找包含公司类型关键词的文本
        for text_pos in text_positions:
            text = text_pos['text']
            if any(keyword in text for keyword in ['有限责任公司', '股份有限公司', '独资', '合伙']):
                self.logger.info(f"找到公司类型: {text}")
                return text
        return None

    def _extract_registered_address_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """优化的注册地址提取 - V2"""
        # 策略1: 从包含"住所"的文本块中直接提取地址
        for text_pos in text_positions:
            text = text_pos['text']
            if '所' in text and ('市' in text or '区' in text):
                # 使用正则提取地址，移除"住所"前缀
                address_pattern = r'住?所?([^。]{5,50}(?:市|区|县|路|街|道|号|室|层|幢).*?)(?:[。]|$)'
                matches = re.findall(address_pattern, text)
                if matches:
                    address = matches[0].strip()
                    if len(address) > 5:
                        self.logger.info(f"V2从住所字段提取地址: {address}")
                        return address

        # 策略2: 寻找包含地址关键词的文本，排除编号等干扰项
        for text_pos in text_positions:
            text = text_pos['text']
            if (any(keyword in text for keyword in ['市', '区', '路', '号', '街', '道']) and
                len(text) > 8 and
                not any(exclude in text for exclude in ['编号', '代码', '信用', '社会', '公司', '企业'])):
                self.logger.info(f"V2直接找到注册地址: {text}")
                return text

        return None
    def _extract_unified_social_credit_code_optimized(self, text_positions: List[Dict], keywords: List[str]) -> Optional[str]:
        """统一社会信用代码专项优化提取"""
        # 策略1: 直接寻找18位代码模式
        for text_pos in text_positions:
            text = text_pos['text']
            # 匹配18位统一社会信用代码
            credit_code_pattern = r'([0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10})'
            matches = re.findall(credit_code_pattern, text)
            if matches:
                self.logger.info(f"V2直接匹配统一社会信用代码: {matches[0]}")
                return matches[0]

        # 策略2: 从包含"统一社会信用代码"关键词的文本中提取
        for text_pos in text_positions:
            text = text_pos['text']
            if '统一社会信用代码' in text:
                # 移除关键词，提取剩余的代码部分
                remaining = text.replace('统一社会信用代码', '').strip()
                # 验证是否为有效的18位代码
                if len(remaining) == 18 and re.match(r'^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$', remaining):
                    self.logger.info(f"V2从关键词文本提取统一社会信用代码: {remaining}")
                    return remaining

                # 尝试从文本中找到18位代码
                code_pattern = r'([0-9A-HJ-NPQRTUWXY]{18})'
                matches = re.findall(code_pattern, remaining)
                if matches:
                    self.logger.info(f"V2从关键词文本匹配统一社会信用代码: {matches[0]}")
                    return matches[0]

        return None

    def _extract_registration_authority_optimized(self, text_positions: List[Dict]) -> Optional[str]:
        """登记机关优化提取"""
        # 常见登记机关模式
        authority_patterns = [
            r'(.*?市场监督管理局)',
            r'(.*?工商行政管理局)',
            r'(.*?市场监管局)',
            r'(.*?工商局)'
        ]

        for text_pos in text_positions:
            text = text_pos['text']

            # 策略1: 寻找包含"登记机关"的文本附近
            if '登记机关' in text:
                # 查找后续文本块中的机关名称
                for other_pos in text_positions:
                    other_text = other_pos['text']
                    for pattern in authority_patterns:
                        matches = re.findall(pattern, other_text)
                        if matches:
                            authority = matches[0]
                            self.logger.info(f"V2找到登记机关: {authority}")
                            return authority

            # 策略2: 直接匹配机关名称模式
            for pattern in authority_patterns:
                matches = re.findall(pattern, text)
                if matches:
                    authority = matches[0]
                    self.logger.info(f"V2直接匹配登记机关: {authority}")
                    return authority

        return None

    def _extract_old_version_date_from_fragments(self, text_positions: List[Dict], keywords: List[str]) -> Optional[str]:
        """从碎片化的文本中提取日期信息

        老版营业执照的日期可能被OCR拆分为多个文本块

        Args:
            text_positions: 文本位置映射
            keywords: 日期相关的关键词

        Returns:
            Optional[str]: 提取的日期
        """
        # 查找关键词位置
        keyword_positions = []
        for i, text_pos in enumerate(text_positions):
            text = text_pos['text']
            for keyword in keywords:
                if keyword in text:
                    keyword_positions.append({'index': i, 'text_pos': text_pos})
                    break

        if not keyword_positions:
            return None

        # 从关键词附近查找日期
        for kp in keyword_positions:
            keyword_index = kp['index']
            keyword_y = kp['text_pos']['center_y']

            # 收集同一行或相近行的文本
            date_candidates = []
            search_range = 5  # 查找范围

            for i in range(max(0, keyword_index - search_range),
                          min(len(text_positions), keyword_index + search_range + 1)):
                text_pos = text_positions[i]
                y_diff = abs(text_pos['center_y'] - keyword_y)

                # 如果在合理范围内
                if y_diff <= text_pos['height'] * 2:
                    text = text_pos['text']
                    # 检查是否包含日期信息
                    if self._contains_date_info(text):
                        date_candidates.append(text)

            # 合并日期候选
            if date_candidates:
                merged_date = ''.join(date_candidates)
                # 提取标准化日期
                normalized_date = self._normalize_date_format(merged_date)
                if normalized_date:
                    return normalized_date

        return None

    def _extract_old_version_address_precise(self, text_positions: List[Dict]) -> Optional[str]:
        """精确提取老版营业执照的住所地址

        Args:
            text_positions: 文本位置映射

        Returns:
            Optional[str]: 地址信息
        """
        # 查找住所关键词
        address_keywords = ['住', '住所', '企业住所', '地址']

        for i, text_pos in enumerate(text_positions):
            text = text_pos['text']

            # 如果找到住所关键词
            for keyword in address_keywords:
                if keyword in text:
                    # 收集地址信息
                    address_parts = []
                    keyword_y = text_pos['center_y']

                    # 查找同行或下面几行的地址内容
                    for j in range(i, min(len(text_positions), i + 8)):
                        addr_text_pos = text_positions[j]
                        y_diff = abs(addr_text_pos['center_y'] - keyword_y)

                        if y_diff <= addr_text_pos['height'] * 3:
                            addr_text = addr_text_pos['text'].strip()

                            # 跳过关键词本身
                            if addr_text == keyword:
                                continue

                            # 如果包含地址特征
                            if self._is_likely_address_text(addr_text):
                                address_parts.append(addr_text)

                    if address_parts:
                        full_address = ''.join(address_parts)
                        # 清理地址文本
                        cleaned_address = re.sub(r'^[住所地址]*', '', full_address).strip()
                        if len(cleaned_address) > 3:
                            return cleaned_address

        return None

    def _contains_date_info(self, text: str) -> bool:
        """检查文本是否包含日期信息"""
        date_indicators = [
            r'\d{4}年', r'\d{1,2}月', r'\d{1,2}日',
            r'年', r'月', r'日',
            r'\d{4}-\d{2}-\d{2}',
            r'二\S*年', r'一\S*月', r'长期', r'永久'
        ]

        for pattern in date_indicators:
            if re.search(pattern, text):
                return True
        return False

    def _is_likely_address_text(self, text: str) -> bool:
        """检查文本是否像地址信息"""
        # 地址常见特征
        address_indicators = [
            '市', '区', '县', '镇', '乡', '街道', '路', '街', '号', '室', '层', '栋', '幢',
            '村', '组', '社区', '小区', '广场', '大厦', '大楼', '中心', '园区'
        ]

        # 排除明显不是地址的内容
        non_address_patterns = [
            r'^\d+$',  # 纯数字
            r'^[一二三四五六七八九十]+$',  # 纯中文数字
            '^成$', '^立$', '^期$', '^限$',  # 单个字符
            '法定代表人', '营业期限', '经营范围', '注册资本'
        ]

        for pattern in non_address_patterns:
            if re.match(pattern, text):
                return False

        # 包含地址指示词
        for indicator in address_indicators:
            if indicator in text:
                return True

        # 长度合理的中文文本可能是地址
        if len(text) > 5 and re.search(r'[\u4e00-\u9fff]', text):
            return True

        return False

